package com.oocl.euc.dao.impl;

import java.util.List;
import java.util.Objects;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.oocl.euc.pagination.BaseConditionQuery;
import com.oocl.euc.pagination.SearchFilter;
import com.oocl.euc.util.ModelUtils;

public abstract class CommonRepository<T> {
	@Autowired
	protected MongoTemplate mongoTemplate;
	
	protected Logger logger = LogManager.getLogger(getClass().getName());
	
	 @SuppressWarnings({"unchecked" })
	private Class<T> targetClass=ModelUtils.getUniquenessGenericClass(getClass());
	 
	 public Page<T> findAll(BaseConditionQuery<T> baseConditionQuery) {
		 Objects.requireNonNull(baseConditionQuery);
		 SearchFilter[] filters=baseConditionQuery.getSearchFilters();
		 Query query=new Query();
		 Criteria criteria=new Criteria();
		 Criteria[] criterias=null;
		 if(filters!=null){
			 criterias=new Criteria[filters.length];
			 int i=0;
			 for(SearchFilter filter:filters){
				 switch (filter.getOperator().toString()) {
				case "EQ":
					criterias[i]=Criteria.where(filter.getFieldName()).is(filter.getValue());
					break;
				case "LIKE":
					criterias[i]=Criteria.where(filter.getFieldName()).regex(".*?"+filter.getValue()+".*", "i");
					break;
				case "GT":
					criterias[i]=Criteria.where(filter.getFieldName()).gt(filter.getValue());
					break;
				case "GTE":
					criterias[i]=Criteria.where(filter.getFieldName()).gte(filter.getValue());
					break;
				case "LT":
					criterias[i]=Criteria.where(filter.getFieldName()).lt(filter.getValue());
					break;
				case "LTE":
					criterias[i]=Criteria.where(filter.getFieldName()).lte(filter.getValue());
					break;
				case "IN":
					criterias[i]=Criteria.where(filter.getFieldName()).in((Object[])filter.getValue().toString().split(","));
				default:
					break;
				}
				 i++;
			 }
			 criteria.andOperator(criterias);
			 query.addCriteria(criteria);
		 }
		 Long count=mongoTemplate.count(query, targetClass);
		 Pageable pageable=baseConditionQuery.getPageable();
		
		 Page<T> pagelist = new PageImpl<T>(mongoTemplate.find(query.with(pageable), targetClass), pageable, count);
		 return pagelist;
	}
	
	public Integer save(T entity) {
		try {
			mongoTemplate.save(entity);
		} catch (Exception e) {
			logger.error(e);
			return 0;
		}
		return 1;
	}
	
	public Integer delete(T entity) {
		try {
			mongoTemplate.remove(entity);
		} catch (Exception e) {
			logger.error(e);
			return 0;
		}
		return 1;
	}
	
	public T findById(Object id){
		T entity=null;
		try {
			entity = mongoTemplate.findById(id, targetClass);
		} catch (Exception e) {
			logger.error(e);
		}
		return entity;
	}
	
	public List<T> findAll() {
		List<T> collection=null;
		try {
			collection = mongoTemplate.findAll(targetClass);
		} catch (Exception e) {
			logger.error(e);
		}
		return collection;
	}
	
	public List<T> find(Criteria criteria){
		List<T> list=null;
		try {
			list = mongoTemplate.find(new Query(criteria), targetClass);
		} catch (Exception e) {
			logger.error(e);
		}
		return list;
	}
	
	public Integer findAndModify(Criteria criteria, Update update){
		T entity=null;
		try {
			entity = mongoTemplate.findAndModify(new Query(criteria), update, targetClass);
		} catch (Exception e) {
			logger.error(e);
			return 0;
		}
		return 1;
	}
	
	public Boolean exists(Query query){
		return mongoTemplate.exists(query, targetClass);
	}
	
	public T findOne(Query query){
		return mongoTemplate.findOne(query, targetClass);
	}
}
